#include "Test.Font.h"

#undef  APP_NAME
#define APP_NAME	TestSensorGyro
#undef  APP_BASE
#define APP_BASE	TestFont



class APP_NAME : public APP_BASE
{
private:
	typedef SHARED_POINTER_TYPE( APP_NAME )		TestSensorGyroPtr;

	struct SensorData
	{
		SysEvent::time_t	lastTime;

		vec3	vec;
		vec3	delta;
		float	counter;
		float	timeDelta;
		///
		SensorData () : counter(0.0f), timeDelta(0.0f) {}

		void Update (const vec3 &value, const SysEvent::time_t time)
		{
			const float	dt = (float) (time - lastTime).ToDouble().GetSec();
			
			if ( timeDelta > 1.0f )
			{
				vec			 = vec3();
				delta		 = vec3();
				timeDelta	 = 0.0f;
				counter		 = 0.0f;
			}

			counter++;
			timeDelta	+= dt;
			delta		+= vec - value;
			vec			 = value;
			lastTime	 = time;
		}

		vec3 GetVec ()	const	{ return vec; }

		vec3 GetDelta () const	{ return counter < 1.0f ? vec3() : delta / counter; }
	};


private:
	SensorData	gyro;
	SensorData	orient;
	SensorData	rotation;
	SensorData	magnetic;


public:
	APP_NAME (IPlatform *platform, EDevice::type deviceType) :
		APP_BASE( platform, deviceType )
	{
		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnGyroscope ),	ESystemEvent::GYROSCOPE );

		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnRotation ),		ESystemEvent::ROTATION );

		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnOrientation ),	ESystemEvent::ORIENTATION );

		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnMagnetic ),		ESystemEvent::MAGNETIC );
	}


	~APP_NAME ()
	{
		ESS()->GetEventSystem()->DetachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnGyroscope ),	ESystemEvent::GYROSCOPE );

		ESS()->GetEventSystem()->DetachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnRotation ),		ESystemEvent::ROTATION );

		ESS()->GetEventSystem()->DetachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnOrientation ),	ESystemEvent::ORIENTATION );

		ESS()->GetEventSystem()->DetachEventListener(
			DelegateBuilder::Create( TestSensorGyroPtr(this), &APP_NAME::_OnMagnetic ),		ESystemEvent::MAGNETIC );
	}


	void Update (float dt) override
	{
		TestApp::Update( dt );
		
		ESS()->GetGraphicsEngine()->GetViewport()->Apply();
		ESS()->GetGLStateManager()->ClearColor( color4f( 0.0f ) );
		
		string	str;

#		define F( x )	string().FormatF( x, StringFormatF().Fmt(0,2) )

		vec3	g = gyro.GetVec();
		vec3	o = orient.GetVec();
		vec3	r = rotation.GetVec();
		vec3	m = magnetic.GetVec();

		str << "gyro:\n" << F( g.x ) << "\n" << F( g.y ) << "\n" << F( g.z )
			<< "\n\norient:\n" << F( o.x ) << "\n" << F( o.y ) << "\n" << F( o.z )
			<< "\n\nrotation:\n" << F( r.x ) << "\n" << F( r.y ) << "\n" << F( r.z )
			<< "\n\nmagnetic:\n" << F( m.x ) << "\n" << F( m.y ) << "\n" << F( m.z );

#		undef F
		
		fontBatch.Draw( vec2(-0.3f, 0.8f), str );

		batch.Flush();
		batch.Clear();
		
		ESS()->GetGraphicsEngine()->SwapBuffers();
	}
	

	void OnEnter () override
	{
		APP_BASE::OnEnter();
		
		fontBatch.SetScale( fontBatch.GetScale() * 0.75f );

		GetPlatform()->EnableSensor( ESensor::GYROSCOPE );
		GetPlatform()->EnableSensor( ESensor::ROTATION );
		GetPlatform()->EnableSensor( ESensor::ORIENTATION );
		GetPlatform()->EnableSensor( ESensor::MAGNETIC_FIELD );
		GetPlatform()->EnableSensor( ESensor::ACCELEROMETER );
	}

	
	void _OnGyroscope (const SysEvent &ev)
	{
		const vec3	v( ev.gyro.x, ev.gyro.y, ev.gyro.z );

		gyro.Update( v, ev.timestamp );

		DEBUG_CONSOLE( (string("gyro - x:") << v.x << ", y:" << v.y << ", z:" << v.z ).cstr() );
	}

	
	void _OnRotation (const SysEvent &ev)
	{
		const vec3	v( ev.rotation.x, ev.rotation.y, ev.rotation.z );

		rotation.Update( v, ev.timestamp );

		DEBUG_CONSOLE( (string("rotation - x:") << v.x << ", y:" << v.y << ", z:" << v.z ).cstr() );
	}

	
	void _OnOrientation (const SysEvent &ev)
	{
		const vec3	v( ev.orient.x, ev.orient.y, ev.orient.z );

		orient.Update( v, ev.timestamp );

		DEBUG_CONSOLE( (string("orient - x:") << v.x << ", y:" << v.y << ", z:" << v.z ).cstr() );
	}

	
	void _OnMagnetic (const SysEvent &ev)
	{
		const vec3	v( ev.magnetic.x, ev.magnetic.y, ev.magnetic.z );

		magnetic.Update( v, ev.timestamp );

		DEBUG_CONSOLE( (string("magnetic - x:") << v.x << ", y:" << v.y << ", z:" << v.z ).cstr() );
	}
};